#define _WIN32_DCOM
#include <windows.h>
#include <iostream.h>
#include <stdio.h>
#include <iaccess.h>  // For IAccessControl

// Need to define this ourselves!
const IID IID_IAccessControl = {0xEEDD23E0,0x8410,0x11CE,{0xA1,0xC3,0x08,0x00,0x2B,0x2B,0x8D,0x8F}};

typedef struct
{
    WORD version;
    WORD pad;
    GUID classid;
} SPermissionHeader;

void main()
{
    HRESULT hr = CoInitialize(NULL);
    if(FAILED(hr))
		cout << "Couldn't initialize COM" << endl;

	// Print out the CLSID of CLSID_DCOMAccessControl
	char buffer[39];
	OLECHAR ppsz[39];
	StringFromGUID2(CLSID_DCOMAccessControl, ppsz, 39);
	WideCharToMultiByte(CP_ACP, 0, ppsz, 39, buffer, 39, NULL, NULL);
	cout << "CLSID_DCOMAccessControl is " << buffer << endl;

    // Create an DCOM access control object and get its IAccessControl interface
    cout << "Creating an instance of CLSID_DCOMAccessControl" << endl;
    IAccessControl* pAccessControl = NULL;     
    hr = CoCreateInstance(CLSID_DCOMAccessControl, NULL, CLSCTX_INPROC_SERVER,
		IID_IAccessControl, (void**)&pAccessControl);
    if(FAILED(hr))
		cout << "Couldn't create DCOM access control object" << endl;

    // Setup the property list. We use the NULL property because we are
    // trying to adjust the security of the object itself
    ACTRL_ACCESSW access;
    ACTRL_PROPERTY_ENTRYW propEntry;
    access.cEntries = 1;
    access.pPropertyAccessList = &propEntry;
    
    ACTRL_ACCESS_ENTRY_LISTW entryList;
    propEntry.lpProperty = NULL;
    propEntry.pAccessEntryList = &entryList;
    propEntry.fListFlags = 0;

    // Setup the access control list for the default property
    ACTRL_ACCESS_ENTRYW entry;
    entryList.cEntries = 1;
    entryList.pAccessList = &entry;

    // Setup the access control entry
    entry.fAccessFlags = ACTRL_ACCESS_ALLOWED;
    entry.Access = COM_RIGHTS_EXECUTE;
    entry.ProvSpecificAccess = 0;
    entry.Inheritance = NO_INHERITANCE;
    entry.lpInheritProperty = NULL;

    // NT requires the system account to have access (for launching)
    entry.Trustee.pMultipleTrustee = NULL;
    entry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
    entry.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    entry.Trustee.TrusteeType = TRUSTEE_IS_USER;
    entry.Trustee.ptstrName = L"NT Authority\\System";

    cout << "Setting access rights: Allow access to NT Authority\\System" << endl;
    hr = pAccessControl->SetAccessRights(&access);
    if(FAILED(hr))
		cout << "Couldn't set access" << endl;

    // Deny access to a user
    entry.fAccessFlags = ACTRL_ACCESS_DENIED;
    entry.Trustee.TrusteeType = TRUSTEE_IS_USER;
    entry.Trustee.ptstrName = L"Domain\\Administrator";

    wprintf(L"Setting access rights: Deny access to %s\n",  entry.Trustee.ptstrName);
    hr = pAccessControl->GrantAccessRights(&access);
    if(FAILED(hr))
		cout << "Couldn't deny access" << endl;

    // Grant access to everyone
    entry.fAccessFlags = ACTRL_ACCESS_ALLOWED;
    entry.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    entry.Trustee.ptstrName = L"*";

    cout << "Setting access rights: Allow access to *" << endl;
    hr = pAccessControl->GrantAccessRights(&access);
    if(FAILED(hr))
		cout << "Couldn't allow access" << endl;

    // Get IPersistStream interface from the DCOM access control object
    cout << "Saving access list to registry key" << endl;
	IPersistStream* pPersistStream = NULL;
	hr = pAccessControl->QueryInterface(IID_IPersistStream, (void**)&pPersistStream);
    if(FAILED(hr))
		cout << "Couldn't get IPersistStream" << endl;

    // Find out how large the access control security buffer is
    ULARGE_INTEGER size;
    hr = pPersistStream->GetSizeMax(&size);
    if(FAILED(hr))
		cout << "Couldn't get size of security buffer" << endl;
    SPermissionHeader header;
    size.QuadPart += sizeof(SPermissionHeader);
    
    // Create a stream where we can place the access control's security buffer
    void* memory = CoTaskMemAlloc(size.LowPart);
    if(memory == 0)
    {
        cout << "Couldn't allocate memory for security buffer" << endl;
        exit(0);
    }
    
    IStream* pStream;
    hr = CreateStreamOnHGlobal(memory, TRUE, &pStream);
    if(FAILED(hr))
		cout << "Couldn't create security buffer stream" << endl;

    // Write the header to the stream
    header.version = 2;
    header.classid = CLSID_DCOMAccessControl;
    hr = pStream->Write(&header, sizeof(header), NULL);
    if(FAILED(hr))
	    cout << "Couldn't write header to stream" << endl;

    // Write the access control security buffer to the stream
    hr = pPersistStream->Save(pStream, TRUE);
    if(FAILED(hr))
	    cout << "Couldn't persist access control information" << endl;

	//	Your AppID below...
    DWORD ignore;
    HKEY key = 0;
    hr = RegCreateKeyEx(HKEY_CLASSES_ROOT, "AppID\\{10000002-0000-0000-0000-000000000001}",
		NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, &ignore);
    if(FAILED(hr))
	    cout << "Couldn't create the AppID key" << endl;

    // Throw everything into the registry
    hr = RegSetValueEx(key, "AccessPermission", NULL, REG_BINARY, (UCHAR*)memory, size.LowPart);
    if(FAILED(hr))
	    cout << "Couldn't write security buffer to registry" << endl;

    // Release everything and bail out
    pPersistStream->Release();
    pStream->Release();
    pAccessControl->Release();

    RegCloseKey(key);
    CoUninitialize();
}